package com.hyt.it.ogt.ykcj.service.grade.impl;


import cn.hutool.core.thread.ThreadUtil;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.hyt.common.apiInfor.ApiResponse;
import com.hyt.it.ogt.common.config.GlobalConfig;
import com.hyt.it.ogt.pj.feign.cloudefile.PushTaskClient;
import com.hyt.it.ogt.pj.feign.cloudefile.RecordClient;
import com.hyt.it.ogt.ykcj.common.enums.FileType;
import com.hyt.it.ogt.ykcj.domain.exam.ExamInfo;
import com.hyt.it.ogt.ykcj.domain.exam.ExamStemInfo;
import com.hyt.it.ogt.ykcj.domain.exam.ExamSubjectInfo;
import com.hyt.it.ogt.ykcj.domain.param.ImportQueryParam;
import com.hyt.it.ogt.ykcj.domain.vo.ExcelRowResultVo;
import com.hyt.it.ogt.ykcj.domain.vo.ExcelRowVo;
import com.hyt.it.ogt.ykcj.domain.vo.ImportInfoVo;
import com.hyt.it.ogt.ykcj.feign.cloudfile.RecordDetailClient;
import com.hyt.it.ogt.ykcj.feign.cloudfile.RecordDetilVerifyClient;
import com.hyt.it.ogt.ykcj.mapper.exam.ExamInfoMapper;
import com.hyt.it.ogt.ykcj.service.exam.IExamSubjectInfoService;
import com.hyt.it.ogt.ykcj.service.grade.IImportEnterpriseExamineeInfoService;
import com.hyt.it.ogt.ykcj.utils.ExecutorPoolUtil;
import com.hyt.loginfo.service.IBaseLoginService;
import com.hyt.model.cloudefile.apiparams.*;
import com.hyt.model.cloudefile.entity.CloudeFileProjectDetailVerify;
import com.hyt.model.cloudefile.entity.CloudeFileProjectRecord;
import com.hyt.model.cloudefile.entity.CloudeFileProjectRecordDetail;
import com.hyt.model.cloudefile.enums.*;
import com.hyt.model.cloudefile.responsedto.FileRecodeDetailStatisticsDto;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.StringUtils;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.Cell;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.io.IOException;
import java.io.InputStream;
import java.math.BigDecimal;
import java.net.HttpURLConnection;
import java.net.URL;
import java.util.*;
import java.util.concurrent.Future;
import java.util.concurrent.TimeUnit;
import java.util.stream.Collectors;


/**
 * 企业招聘考生信息Service业务层处理
 *
 * @author liying
 * @date 2021-11-19
 */
@Service
public class ImportEnterpriseExamineeInfoServiceImpl implements IImportEnterpriseExamineeInfoService {
    private static final Logger log = LoggerFactory.getLogger(ImportEnterpriseExamineeInfoServiceImpl.class);

    @Autowired
    private ExamInfoMapper examInfoMapper;

    @Autowired
    private PushTaskClient pushTaskClient;


    @Autowired
    private IBaseLoginService iBaseLoginService;

    @Autowired
    private IExamSubjectInfoService examSubjectInfoService;


    @Autowired
    private EnterpriseExamineeInfoExportUtil enterpriseExamineeInfoExportUtil;

    @Resource
    GlobalConfig globalConfig;


    @Autowired
    private RecordClient recordClient;


    @Autowired
    private RecordDetailClient recordDetailClient;


    @Autowired
    private RecordDetilVerifyClient recordDetilVerifyClient;

    /**
     * 导入数据
     *
     * @param examId
     * @param subjectId
     */
    @Override
    public Object[] readExcelFile(String filePath, String examId, String subjectId) {
        ApiResponse<Boolean> apiResponse = null;
        try {
            //新增校验任务
            PushTaskParam pushTaskParam = new PushTaskParam();
            pushTaskParam.setProjectId(examId);
            pushTaskParam.setSystemType(SystemEnum.YKCJ.getSystemType());
            pushTaskParam.setOperateType(OperateTypeEnum.FILE_UPLOAD.getOperateType());
            pushTaskParam.setFileType(FileTypeEnum.YKCJ.getFileType());
            pushTaskParam.setFileKey(JobKeyEnum.CJIMPORTJOB.getKey());
            pushTaskParam.setExecuteImmediately(Boolean.TRUE);
            pushTaskParam.setOfficeId(iBaseLoginService.getOfficeId());
            pushTaskParam.setDeptId(iBaseLoginService.getDeptId());
            pushTaskParam.setFileUrl(filePath);
            if (StringUtils.isNotEmpty(subjectId)) {
                Map<String, Object> dynamicAttr = new HashMap<>();
                dynamicAttr.put("subjectId", subjectId);
                pushTaskParam.setDynamicAttr(dynamicAttr);
            }

            apiResponse = pushTaskClient.pushTask(pushTaskParam);

        } catch (Exception e) {
            log.error("导入成绩出现异常：", e);
            return new Object[]{Boolean.FALSE, "系统异常，导入失败"};
        }
        return new Object[]{Boolean.TRUE, null == apiResponse ? Boolean.TRUE : apiResponse.getData()};
    }


    @Override
    public Object[] importExcelFile(String filepath, String examId, String subjectId) {
        InputStream fis = null;
        ApiResponse<Boolean> apiResponse = null;
        try {
            fis = getInputStreamFromUrl(filepath);   //文件流对象
            // 开始解析
            Sheet sheet = getSheet(fis, filepath);     // 读取sheet 0

            Map<String, BigDecimal> scoreMap = new HashMap<>();
            List<String> keys = new ArrayList<>(Arrays.asList(new String[]{"admissionNo", "name", "sex", "idcard", "mobile", "education"}));
            List<String> titles = new ArrayList<>(Arrays.asList(new String[]{"准考证号", "姓名", "性别", "证件号", "手机号码", "学历"}));
            String msg = checkExamineeOrigin(examId, subjectId, sheet, keys, titles, scoreMap);
            if (StringUtils.isNotEmpty(msg)) {
                return new Object[]{Boolean.FALSE, msg};
            }
            //新增校验任务
            PushTaskParam pushTaskParam = new PushTaskParam();
            pushTaskParam.setProjectId(examId);
            pushTaskParam.setFileUrl(filepath);
            pushTaskParam.setSystemType(SystemEnum.YKCJ.getSystemType());
            pushTaskParam.setOperateType(OperateTypeEnum.FILE_UPLOAD.getOperateType());
            pushTaskParam.setFileType(FileTypeEnum.YKCJ.getFileType());
            pushTaskParam.setFileKey(JobKeyEnum.CJIMPORTCKECKJOB.getKey());
            pushTaskParam.setExecuteImmediately(Boolean.TRUE);
            pushTaskParam.setOfficeId(iBaseLoginService.getOfficeId());
            pushTaskParam.setDeptId(iBaseLoginService.getDeptId());
            if (StringUtils.isNotEmpty(subjectId)) {
                Map<String, Object> dynamicAttr = new HashMap<>();
                dynamicAttr.put("subjectId", subjectId);
                pushTaskParam.setDynamicAttr(dynamicAttr);
            }

            apiResponse = pushTaskClient.pushTask(pushTaskParam);

        } catch (Exception e) {
            log.error("导入成绩出现异常：", e);
            return new Object[]{Boolean.FALSE, "系统异常，导入失败"};
        } finally {
            try {
                if (null != fis) {
                    fis.close();
                    log.info("文件流关闭成功");
                }
            } catch (Exception e) {
                log.info("文件流关闭失败！");
            }
        }


        return new Object[]{Boolean.TRUE, null == apiResponse ? Boolean.TRUE : apiResponse.getData()};
    }


    private String checkExamineeOrigin(String examId, String subjectId, Sheet sheet, List<String> keys, List<String> titles,
                                       Map<String, BigDecimal> scoreMap) {
        if (StringUtils.isEmpty(examId)) {
            return "考试数据不存在";
        }
        if (null == sheet) {
            return "文件类型不正确";
        }
        int headRowIndex = sheet.getFirstRowNum();
        Row headRow = sheet.getRow(headRowIndex);
        if (null == headRow || sheet.getLastRowNum() <= 0) {
            return "导入文件无数据";
        }

        ExamInfo examInfo = examInfoMapper.selectById(examId);
        if (null == examInfo) {
            return "考试数据不存在";
        }
        if (StringUtils.isNotEmpty(examInfo.getOrigin()) && "1".equals(examInfo.getOrigin())) {
            return "云考试数据，系统暂时不能操作";
        }
        int fixedCellNum = 6; // 固定列数
        int firstCellIndex = headRow.getFirstCellNum(); // 开始列下标
        int lastCellIndex = headRow.getLastCellNum(); // 最后列下标
        List<ExamSubjectInfo> subjectList = examSubjectInfoService.getExamSubjectInfos(examId, subjectId);

        if (CollectionUtils.isNotEmpty(subjectList)) {
            fixedCellNum = fixedCellNum + subjectList.size();
            for (ExamSubjectInfo subjectVo : subjectList) {
                if (CollectionUtils.isNotEmpty(subjectVo.getExamStemInfos())) {
                    fixedCellNum = fixedCellNum + subjectVo.getExamStemInfos().size();
                }
            }
            if (lastCellIndex != fixedCellNum) {
                return "导入文件列数与模板设定不一致，请检查!";
            }
            for (ExamSubjectInfo subjectVo : subjectList) {
                titles.add(subjectVo.getSubjectName());
                keys.add("KM_" + subjectVo.getId());
                scoreMap.put("KM_" + subjectVo.getId(), subjectVo.getPaperFullMarks());
                if (CollectionUtils.isEmpty(subjectVo.getExamStemInfos())) {
                    continue;
                }
                for (ExamStemInfo stemScoreVo : subjectVo.getExamStemInfos()) {
                    titles.add(stemScoreVo.getName());
                    keys.add(subjectVo.getId() + "TG_" + stemScoreVo.getId());
                    scoreMap.put(subjectVo.getId() + "TG_" + stemScoreVo.getId(), stemScoreVo.getTotalPoints());
                }
            }

        }

        for (int cIndex = firstCellIndex; cIndex < lastCellIndex; cIndex++) {   //遍历列
            Cell cell = headRow.getCell(cIndex);
            if (cell == null) {
                continue;
            }
            if (!cell.toString().equals(titles.get(cIndex))) {
                return "导入文件第" + (cIndex + 1) + "列【" + cell.toString() + "】的列名或顺序与模板设定【" + titles.get(cIndex) + "】的列名不一致，请检查!";
            }

        }


        return null;
    }


    private Sheet getSheet(InputStream fis, String filepath) throws Exception {
        log.info("文件存在，已判断文件存在，进入excel解析阶段");
        String[] split = filepath.split("\\.");  //.是特殊字符，需要转义！！！！！
        Workbook wb = null;
        //根据文件后缀（xls/xlsx）进行判断
        if (FileType.FILE_TYPE_XLS.getType().replace(".", "").equals(split[split.length - 1].toLowerCase())) {
            wb = new HSSFWorkbook(fis);
        } else if (FileType.FILE_TYPE_XLSX.getType().replace(".", "").equals(split[split.length - 1].toLowerCase())) {
            wb = new XSSFWorkbook(fis);
        } else {
            return null;
        }
        // 开始解析
        Sheet sheet = wb.getSheetAt(0);
        return sheet;

    }

    /**
     * 根据url下载文件流
     *
     * @param urlStr
     * @return
     */
    public static InputStream getInputStreamFromUrl(String urlStr) {
        InputStream inputStream = null;
        try {
            //url解码
            URL url = new URL(urlStr);
            HttpURLConnection conn = (HttpURLConnection) url.openConnection();
            //得到输入流
            inputStream = conn.getInputStream();
        } catch (IOException e) {
            log.info("获取文件getInputStreamFromUrl异常:{}", e);
        }
        return inputStream;
    }


    @Override
    public Boolean checkExecuteExcelFile(String examId) {

        FileRecodeParam fileRecodeParam = new FileRecodeParam();
        fileRecodeParam.setProjectId(examId);
        fileRecodeParam.setSystemType(SystemEnum.YKCJ.getSystemType());
        ApiResponse<Object> apiResponse = recordClient.queryfileRecode(fileRecodeParam);
        if (null != apiResponse.getData()) {
            String jsonData = JSON.toJSONString(apiResponse.getData());
            List<CloudeFileProjectRecord> queryResult = JSON.parseArray(jsonData, CloudeFileProjectRecord.class);
            List<String> statuss = queryResult.stream().map(c -> c.getStatus()).collect(Collectors.toList());
            if (statuss.contains(FileStatusEnum.PROCESSING.getStatus())) {
                return Boolean.FALSE;
            }
        }
        return Boolean.TRUE;
    }


    @Override
    public String exportExcelByCondition(ImportQueryParam queryParamDto) {
        FileRecodeDetailParam fileRecodeParam = new FileRecodeDetailParam();
        fileRecodeParam.setProjectId(queryParamDto.getExamId());
        fileRecodeParam.setPageNo(null == queryParamDto.getPageNo() ? 1 : queryParamDto.getPageNo());
        fileRecodeParam.setPageSize(null == queryParamDto.getPageSize() ? 1000 : queryParamDto.getPageSize());
        fileRecodeParam.setStatus(FileStatusEnum.FAIL.getStatus());
        fileRecodeParam.setSystemType(SystemEnum.YKCJ.getSystemType());
        if (StringUtils.isNotEmpty(queryParamDto.getSubjectId())) {
            Map<String, Object> dynamicAttr = new HashMap<>();
            dynamicAttr.put("subjectId", queryParamDto.getSubjectId());
            fileRecodeParam.setDynamicAttr(dynamicAttr);
        }
        ApiResponse<Page<CloudeFileProjectRecordDetail>> apiResponse = recordDetailClient.queryfileRecode(fileRecodeParam);
        if (null == apiResponse || null == apiResponse.getData()) {
            return null;
        }
        Page<CloudeFileProjectRecordDetail> page = apiResponse.getData();
        List<CloudeFileProjectRecordDetail> recordDetails = page.getRecords();
        if (CollectionUtils.isEmpty(recordDetails)) {
            return null;
        }
        List<String> titles = JSONArray.parseArray(recordDetails.get(0).getRemark(), String.class);
        List<CloudeFileProjectRecordDetail> allRecordDetails = new ArrayList<>(recordDetails.size());
        allRecordDetails.addAll(recordDetails);
        long total = page.getTotal();
        long batchCount = fileRecodeParam.getPageSize();
        long count = total % batchCount == 0 ? total / batchCount : total / batchCount + 1;
        for (int i = 2; i < count; i++) {
            fileRecodeParam.setPageNo(i);
            apiResponse = recordDetailClient.queryfileRecode(fileRecodeParam);
            if (null == apiResponse || null == apiResponse.getData()) {
                continue;
            }
            page = apiResponse.getData();
            recordDetails = page.getRecords();
            if (CollectionUtils.isEmpty(recordDetails)) {
                continue;
            }
            allRecordDetails.addAll(recordDetails);
        }
        List<String> values = allRecordDetails.stream().filter(e -> StringUtils.isNotEmpty(e.getData())).map(e -> e.getData()).collect(Collectors.toList());
        if (CollectionUtils.isEmpty(values)) {
            return null;
        }
        Future<String> fileFuture = ExecutorPoolUtil.getPoolTaskExecutor().submit(() -> {
            // zip文件URL
            String dbfUrl = null;
            try {
                // 设置导出时候的名称
                String fileName = System.currentTimeMillis() + "_异常数据列表";
                String sheetName = "异常考生数据列表";
                XSSFWorkbook xssfWorkbook = enterpriseExamineeInfoExportUtil.getExamineeXSSFWorkbook(titles, values, sheetName);
                dbfUrl = enterpriseExamineeInfoExportUtil.exportExcelV2(xssfWorkbook, fileName);
            } catch (Exception e) {
                log.error("# 23、上传{}文件异常", "queryEnterpriseExamineeGradeVo.getFileName()", e);
            }

            return dbfUrl;
        });

        String zipUrl = null;
        try {
            zipUrl = ExecutorPoolUtil.getPoolTaskExecutor()
                    .submit(() -> {
                        // 这里浅浅的睡眠100毫秒避免空转
                        while (!fileFuture.isDone()) {
                            ThreadUtil.sleep(100);
                        }
                        return fileFuture.get();
                    }).get(globalConfig.getFileTimeOut(), TimeUnit.SECONDS);
        } catch (Exception e) {
            log.error("# 22、{}文件生成超过指定等待时间，提前返回", "queryEnterpriseExamineeGradeVo.getFileName()");
        }
        if (StringUtils.isNotEmpty(zipUrl)) {
            return zipUrl;
        }

        return null;
    }


    @Override
    public ExcelRowResultVo queryExcelImportInfo(ImportQueryParam queryParamDto) {
        ExcelRowResultVo resultVo = new ExcelRowResultVo();
        resultVo.setComplete("0");
//        FileRecodeDetailStatisticsParam fileRecodeDetailStatisticsParam = new FileRecodeDetailStatisticsParam();
//        fileRecodeDetailStatisticsParam.setProjectId(queryParamDto.getExamId());
//        fileRecodeDetailStatisticsParam.setSystemType(SystemEnum.YKCJ.getSystemType());
//        ApiResponse<FileRecodeDetailStatisticsDto> response =  recordDetailClient.fileRecodeDetailStatisticsV2(fileRecodeDetailStatisticsParam);
//        resultVo.setComplete("0");
//        if(null != response && null != response.getData() && response.getData().getAllItems() > 0){
//            resultVo.setComplete("1");
//        }

        List<ExcelRowVo> excelRowVos = new ArrayList<>();
        FileDetailVerifyParam fileDetailVerifyParam = new FileDetailVerifyParam();
        fileDetailVerifyParam.setProjectId(queryParamDto.getExamId());
        fileDetailVerifyParam.setPageNo(null == queryParamDto.getPageNo() ? 1 : queryParamDto.getPageNo());
        fileDetailVerifyParam.setPageSize(null == queryParamDto.getPageSize() ? 20 : queryParamDto.getPageSize());


        fileDetailVerifyParam.setSystemType(SystemEnum.YKCJ.getSystemType());
        if (StringUtils.isNotEmpty(queryParamDto.getSubjectId())) {
            Map<String, Object> dynamicAttr = new HashMap<>();
            dynamicAttr.put("subjectId", queryParamDto.getSubjectId());
            fileDetailVerifyParam.setDynamicAttr(dynamicAttr);
        }
        ApiResponse<Page<CloudeFileProjectDetailVerify>> response = recordDetilVerifyClient.queryfileDetialVerifyByPage(fileDetailVerifyParam);
        if (null != response && null != response.getData() && response.getData().getTotal() > 0) {
            resultVo.setComplete("1");
        }

        if ("1".equals(queryParamDto.getFlag())) {
            fileDetailVerifyParam.setVerifyStatus(FileStatusEnum.CHECKSUCCESS.getStatus());
        } else {
            fileDetailVerifyParam.setVerifyStatus(FileStatusEnum.CHECKFAIL.getStatus());
        }

        ApiResponse<Page<CloudeFileProjectDetailVerify>> apiResponse = recordDetilVerifyClient.queryfileDetialVerifyByPage(fileDetailVerifyParam);
        if (null == apiResponse || null == apiResponse.getData()) {
            return resultVo;
        }
        Page<CloudeFileProjectDetailVerify> page = apiResponse.getData();
        List<CloudeFileProjectDetailVerify> detailVerifys = page.getRecords();
        if (CollectionUtils.isEmpty(detailVerifys)) {
            return resultVo;
        }
        excelRowVos.addAll(buildExcelRowVos(detailVerifys));
        resultVo.setTotal(page.getTotal());
        resultVo.setExcelRowVos(excelRowVos);


        return resultVo;
    }


    @Override
    public ImportInfoVo queryExcelImportInfoCount(ImportQueryParam queryParamDto) {
        ImportInfoVo importInfoVo = new ImportInfoVo();
        FileRecodeDetailStatisticsParam fileRecodeParam = new FileRecodeDetailStatisticsParam();
        fileRecodeParam.setProjectId(queryParamDto.getExamId());
        fileRecodeParam.setSystemType(SystemEnum.YKCJ.getSystemType());
        ApiResponse<FileRecodeDetailStatisticsDto> apiResponse = recordDetailClient.queryfileRecodeStatistics(fileRecodeParam);
        if (null == apiResponse || null == apiResponse.getData()) {
            return importInfoVo;
        }

        FileRecodeDetailStatisticsDto detailStatisticsDto = apiResponse.getData();
        if (detailStatisticsDto.getAllItems().intValue() == 0) {
            FileDetailVerifyParam fileDetailVerifyParam = new FileDetailVerifyParam();
            fileDetailVerifyParam.setProjectId(queryParamDto.getExamId());
            fileDetailVerifyParam.setPageNo(null == queryParamDto.getPageNo() ? 1 : queryParamDto.getPageNo());
            fileDetailVerifyParam.setPageSize(null == queryParamDto.getPageSize() ? 20 : queryParamDto.getPageSize());
            fileDetailVerifyParam.setSystemType(SystemEnum.YKCJ.getSystemType());
            if (StringUtils.isNotEmpty(queryParamDto.getSubjectId())) {
                Map<String, Object> dynamicAttr = new HashMap<>();
                dynamicAttr.put("subjectId", queryParamDto.getSubjectId());
                fileDetailVerifyParam.setDynamicAttr(dynamicAttr);
            }
            ApiResponse<Page<CloudeFileProjectDetailVerify>> verifyResponse = recordDetilVerifyClient.queryfileDetialVerifyByPage(fileDetailVerifyParam);
            if (null == verifyResponse || null == verifyResponse.getData()) {
                return importInfoVo;
            }
            Long failNo = 0L;
            Page<CloudeFileProjectDetailVerify> page = verifyResponse.getData();
            List<CloudeFileProjectDetailVerify> detailVerifys = verifyResponse.getData().getRecords();
            if (CollectionUtils.isNotEmpty(detailVerifys)) {
                failNo = detailVerifys.stream().filter(e -> FileStatusEnum.FAIL.getStatus().equals(e.getVerifyStatus())).count();
            }
            importInfoVo.setFailNo(failNo.intValue());
            importInfoVo.setSuccessNo(0);
            importInfoVo.setTotalNo((int) page.getTotal());
            return importInfoVo;
        }
        importInfoVo.setFailNo(detailStatisticsDto.getFailItems());
        importInfoVo.setSuccessNo(detailStatisticsDto.getSuccessItems());
        importInfoVo.setTotalNo(detailStatisticsDto.getAllItems());
        if (null != queryParamDto.getTotalSize() && null != detailStatisticsDto.getAllItems()
                && !queryParamDto.getTotalSize().equals(detailStatisticsDto.getAllItems())) {
            importInfoVo.setTotalNo(queryParamDto.getTotalSize());
        }

        return importInfoVo;
    }


    @Override
    public Boolean removeExcelImportInfo(ImportQueryParam queryParamDto) {
        FileDetailVerifyParam fileDetailVerifyParam = new FileDetailVerifyParam();
        fileDetailVerifyParam.setProjectId(queryParamDto.getExamId());
        fileDetailVerifyParam.setSystemType(SystemEnum.YKCJ.getSystemType());
        ApiResponse<Boolean> response = recordDetilVerifyClient.removefileDetailVerify(fileDetailVerifyParam);
        return response.getData();
    }

    private List<ExcelRowVo> buildExcelRowVos(List<CloudeFileProjectDetailVerify> detailVerifys) {
        List<ExcelRowVo> excelRowVos = new ArrayList<>();
        for (CloudeFileProjectDetailVerify detailVerify : detailVerifys) {
            if (StringUtils.isEmpty(detailVerify.getData())) {
                continue;
            }
            List<String> cellValues = JSONArray.parseArray(detailVerify.getData(), String.class);
            ExcelRowVo excelRowVo = new ExcelRowVo();
            excelRowVo.setAdmissionNo(cellValues.get(0));
            excelRowVo.setMsg(detailVerify.getErrorMsg());
            excelRowVo.setName(cellValues.get(1));
            excelRowVos.add(excelRowVo);
        }
        return excelRowVos;
    }


}
